Function: diff-unified->context

diff-unified->context is an interactive and byte-compiled function defined in diff-mode.el.gz.

Signature

(diff-unified->context START END)

Documentation

Convert unified diffs to context diffs.

START and END are either taken from the region (if a prefix arg is given) or else cover the whole buffer.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/vc/diff-mode.el.gz
;;;;
;;;; Conversion functions
;;;;

;;(defvar diff-inhibit-after-change nil
;;  "Non-nil means inhibit `diff-mode's after-change functions.")

(defun diff-unified->context (start end)
  "Convert unified diffs to context diffs.
START and END are either taken from the region (if a prefix arg is given) or
else cover the whole buffer."
  (interactive (if (or current-prefix-arg (use-region-p))
		   (list (region-beginning) (region-end))
		 (list (point-min) (point-max))))
  (unless (markerp end) (setq end (copy-marker end t)))
  (let (;;(diff-inhibit-after-change t)
	(inhibit-read-only t))
    (save-excursion
      (goto-char start)
      (while (and (re-search-forward
                   (concat "^\\(\\(---\\) .+\n\\(\\+\\+\\+\\) .+\\|"
                           diff-hunk-header-re-unified ".*\\)$")
                   nil t)
		  (< (point) end))
	(combine-after-change-calls
	  (if (match-beginning 2)
	      ;; we matched a file header
	      (progn
		;; use reverse order to make sure the indices are kept valid
		(replace-match "---" t t nil 3)
		(replace-match "***" t t nil 2))
	    ;; we matched a hunk header
	    (let ((line1 (match-string 4))
		  (lines1 (or (match-string 5) "1"))
		  (line2 (match-string 6))
		  (lines2 (or (match-string 7) "1"))
		  ;; Variables to use the special undo function.
		  (old-undo buffer-undo-list)
		  (old-end (marker-position end))
		  (start (match-beginning 0))
		  (reversible t))
	      (replace-match
	       (concat "***************\n*** " line1 ","
		       (number-to-string (+ (string-to-number line1)
					    (string-to-number lines1)
					    -1))
		       " ****"))
	      (save-restriction
		(narrow-to-region (line-beginning-position 2)
                                  ;; Call diff-end-of-hunk from just before
                                  ;; the hunk header so it can use the hunk
                                  ;; header info.
				  (progn (diff-end-of-hunk 'unified) (point)))
		(let ((hunk (buffer-string)))
		  (goto-char (point-min))
		  (if (not (save-excursion (re-search-forward "^-" nil t)))
		      (delete-region (point) (point-max))
		    (goto-char (point-max))
		    (let ((modif nil) last-pt)
		      (while (progn (setq last-pt (point))
				    (= (forward-line -1) 0))
			(pcase (char-after)
			  (?\s (insert " ") (setq modif nil) (backward-char 1))
			  (?+ (delete-region (point) last-pt) (setq modif t))
			  (?- (if (not modif)
                                  (progn (forward-char 1)
                                         (insert " "))
                                (delete-char 1)
                                (insert "! "))
                              (backward-char 2))
			  (?\\ (when (save-excursion (forward-line -1)
                                                     (= (char-after) ?+))
                                 (delete-region (point) last-pt)
                                 (setq modif t)))
                          ;; diff-valid-unified-empty-line.
                          (?\n (insert "  ") (setq modif nil)
                               (backward-char 2))
			  (_ (setq modif nil))))))
		  (goto-char (point-max))
		  (save-excursion
		    (insert "--- " line2 ","
			    (number-to-string (+ (string-to-number line2)
						 (string-to-number lines2)
						 -1))
                            " ----\n" hunk))
		  ;;(goto-char (point-min))
		  (forward-line 1)
		  (if (not (save-excursion (re-search-forward "^\\+" nil t)))
		      (delete-region (point) (point-max))
		    (let ((modif nil) (delete nil))
		      (if (save-excursion (re-search-forward "^\\+.*\n-"
                                                             nil t))
                          ;; Normally, lines in a substitution come with
                          ;; first the removals and then the additions, and
                          ;; the context->unified function follows this
                          ;; convention, of course.  Yet, other alternatives
                          ;; are valid as well, but they preclude the use of
                          ;; context->unified as an undo command.
			  (setq reversible nil))
		      (while (not (eobp))
			(pcase (char-after)
			  (?\s (insert " ") (setq modif nil) (backward-char 1))
			  (?- (setq delete t) (setq modif t))
			  (?+ (if (not modif)
                                  (progn (forward-char 1)
                                         (insert " "))
                                (delete-char 1)
                                (insert "! "))
                              (backward-char 2))
			  (?\\ (when (save-excursion (forward-line 1)
                                                     (not (eobp)))
                                 (setq delete t) (setq modif t)))
                          ;; diff-valid-unified-empty-line.
                          (?\n (insert "  ") (setq modif nil) (backward-char 2)
                               (setq reversible nil))
			  (_ (setq modif nil)))
			(let ((last-pt (point)))
			  (forward-line 1)
			  (when delete
			    (delete-region last-pt (point))
			    (setq delete nil)))))))
		(unless (or (not reversible) (eq buffer-undo-list t))
                  ;; Drop the many undo entries and replace them with
                  ;; a single entry that uses diff-context->unified to do
                  ;; the work.
		  (setq buffer-undo-list
			(cons (list 'apply (- old-end end) start (point-max)
				    'diff-context->unified start (point-max))
			      old-undo)))))))))))